﻿/* 
 * Rug.Cmd part of Rugland Console Framework
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Copyright (C) 2008 Phill Tew. All rights reserved.
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace Rug.Cmd
{
	/// <summary>
	/// Thread safe IConsole implementation that stores console output in a buffer
	/// </summary>
	public class ConsoleBuffer : IConsole
	{
		#region Private Members
		
		private object m_Lock = new object();

		private ConsoleFormatter m_Formatter = new ConsoleFormatter();
		private List<string> m_ConsoleText = new List<string>(24);

		private bool m_EchoToSystemConsole = false;
		private long m_TopLine = 0;
		private string m_Title; 
		private int m_BufferWidth;
		private int m_BufferHeight;
		private Colors.ConsoleColorTheme m_Theme;
		private ConsoleColorExt m_ForegroundColor;
		private ConsoleColorExt m_BackgroundColor;
		private ConsoleColorState m_OriginalState;
		private ConsoleVerbosity m_Verbosity;

		#endregion		

		#region Public Events And Properties

		public event EventHandler ContentsChanged;

		/// <summary>
		/// The absolute index of the top most line in the buffer
		/// </summary>
		public long TopLine { get { lock (m_Lock) { return m_TopLine; } } }

		/// <summary>
		/// The absolute index of the bottom most line
		/// </summary>
		public long BottomLine { get { lock (m_Lock) { return m_TopLine + m_ConsoleText.Count; } } }

		/// <summary>
		/// Should console messages be echoed to the system console
		/// </summary>
		public bool EchoToSystemConsole { get { return m_EchoToSystemConsole; } set { m_EchoToSystemConsole = value; } }

		#endregion

		public ConsoleBuffer()
		{
			m_Title = RC.Sys.Title; 
			m_BufferWidth = RC.Sys.BufferWidth;
			m_BufferHeight = RC.Sys.BufferHeight;
			m_Theme = RC.Sys.Theme;
			m_OriginalState = RC.Sys.ColorState;
			m_Verbosity = RC.Sys.Verbosity;
			m_ForegroundColor = RC.Sys.ForegroundColor;
			m_BackgroundColor = RC.Sys.BackgroundColor; 
		}

		#region Get Lines
		
		/// <summary>
		/// Get a range of lines from the buffer
		/// </summary>
		/// <param name="top">The absolute index of the top line to get</param>
		/// <param name="count">The maximum line count to get</param>
		/// <returns>the lines from the buffer</returns>
		public List<string> GetLines(long top, int count)
		{
			lock (m_Lock)
			{
				if (top < TopLine)
				{
					throw new IndexOutOfRangeException(); 
				}

				int start = (int)(top - TopLine);

				if (start + count > m_ConsoleText.Count)
				{
					count = m_ConsoleText.Count - start;
				}

				return m_ConsoleText.GetRange(start, count);
			}
		}

		/// <summary>
		/// Get a range of lines from the buffer
		/// </summary>
		/// <param name="top">The relitive index of the top line to get</param>
		/// <param name="count">The maximum line count to get</param>
		/// <returns>the lines from the buffer</returns>
		public List<string> GetLines(int start, int count)
		{
			lock (m_Lock)
			{
				if (start + count > m_ConsoleText.Count)
				{
					count = m_ConsoleText.Count - start;
				}

				return m_ConsoleText.GetRange(start, count);
			}
		}

		#endregion

		#region Internal Buffer Write Methods

		private void OnContentsChanged()
		{
			if (ContentsChanged != null)
			{
				ContentsChanged(this, EventArgs.Empty);
			}
		}

		private void AddLines(string[] lines)
		{
			if (m_ConsoleText.Count + lines.Length > m_BufferHeight)
			{
				int diff = (m_ConsoleText.Count + lines.Length) - m_BufferHeight; 

				m_ConsoleText.RemoveRange(0, diff);

				m_TopLine += diff; 
			}

			m_ConsoleText.AddRange(lines); 
		}

		private void BufferFlush()
		{
			if (m_Formatter.Length > 0)
			{
				AddLines(ConsoleFormatter.SplitLines(m_Formatter.ToString(), BufferWidth));

				m_Formatter.Clear();
			}
		}

		private void BufferWriteFormmatted(string formatted)
		{
			BufferFlush();

			AddLines(ConsoleFormatter.SplitLines(formatted, BufferWidth));
		}

		private void BufferWrite(ConsoleColorExt color, string str)
		{
			if (color == ConsoleColorExt.Inhreit)
			{
				color = m_ForegroundColor;
			}

			m_Formatter.Write(color, str);
		}

		private void BufferWrite(string str)
		{
			m_Formatter.Write(m_ForegroundColor, str);
		}

		private void BufferWriteLine(string str)
		{
			m_Formatter.WriteLine(m_ForegroundColor, str);

			BufferFlush();
		}

		private void BufferWriteLine(ConsoleColorExt color, string str)
		{
			if (color == ConsoleColorExt.Inhreit)
			{
				color = m_ForegroundColor;
			}

			m_Formatter.WriteLine(color, str);

			BufferFlush();
		}

		private void BufferWriteWrapped(ConsoleColorExt colour, string message, int paddingLeft, int paddingRight)
		{
			int maxWidth = BufferWidth - (paddingLeft + paddingRight);

			List<string> lines = new List<string>(message.Split(new string[] { Environment.NewLine, "\n" }, StringSplitOptions.None));

			string prefix = new string(' ', paddingLeft);

			foreach (string line in lines)
			{
				string str = line;

				if (str.Length == 0)
				{
					BufferWriteLine("");
				}
				else
				{
					while (str.Length > 0)
					{
						if (str.Length > maxWidth)
						{
							BufferWriteLine(colour, prefix + str.Substring(0, maxWidth));
							str = str.Substring(maxWidth);
						}
						else
						{
							BufferWriteLine(colour, prefix + str);
							str = "";
						}
					}
				}
			}
		}

		private void BufferWriteStackTrace(string trace)
		{
			BufferWriteLine("");
			BufferWriteLine(Theme[ConsoleThemeColor.ErrorColor2], new string(ConsoleChars.GetShade(ConsoleShade.Dim), BufferWidth));
			BufferWriteLine(Theme[ConsoleThemeColor.TitleText], "  " + trace.Replace("\n", "\n  "));
			BufferWriteLine(Theme[ConsoleThemeColor.ErrorColor2], new string(ConsoleChars.GetShade(ConsoleShade.Dim), BufferWidth));
			BufferWriteLine("");
		}

		private void BufferWriteMessage(ConsoleMessage type, ConsoleColorExt colour, string str)
		{
			BufferWriteMessage(type, colour, 0, str);
		}

		private void BufferWriteMessage(ConsoleMessage type, ConsoleThemeColor colour, string str)
		{
			BufferWriteMessage(type, colour, 0, str);
		}

		private void BufferWriteMessage(ConsoleMessage type, ConsoleColorExt colour, int errorId, string str)
		{
			BufferWriteMessage(type, colour, errorId, null, 0, 0, str);
		}

		private void BufferWriteMessage(ConsoleMessage type, ConsoleColorExt colour, int errorId, string sourceFile, int line, int character, string str)
		{
			string realString = str;

			if (IsBuildMode == true)
			{
				string reportType = "";

				if (type == ConsoleMessage.Warning)
				{
					if (WarningsAsErrors == true)
						reportType = "error";
					else
						reportType = "warning";
				}
				else if (type == ConsoleMessage.Prompt)
				{
					if ((this as IConsole).WarningsAsErrors)
						reportType = "error";
					else
						reportType = "warning";
				}
				else
				{
					reportType = "error"; // type.ToString().ToLower();
				}

				string sourceString = null;

				if (sourceFile == null)
				{
					sourceString = Application.ExecutablePath;
				}
				else
				{
					sourceString = sourceFile + "(" + line + "," + character + ")";
				}

				if (reportType != "warning" || (reportType == "warning" && ReportWarnings == true))
				{
					realString = sourceString + ": " + reportType + " " + ApplicationBuildReportPrefix + errorId.ToString().PadLeft(4, '0') + ": " + str.Replace("\n", " ");
				}
			}

			if (CanManipulateBuffer == true)
			{
				if (CursorLeft > 0)
				{
					BufferWriteLine("");
				}

				BufferWriteLine(colour, realString);
			}
			else
			{
				BufferWriteLine(colour, realString);
			}
		}

		private void BufferWriteMessage(ConsoleMessage type, ConsoleThemeColor colour, int errorId, string str)
		{
			BufferWriteMessage(type, colour, errorId, null, 0, 0, str);
		}

		private void BufferWriteMessage(ConsoleMessage type, ConsoleThemeColor colour, int errorId, string sourceFile, int line, int character, string str)
		{
			BufferWriteMessage(type, Theme[colour], errorId, sourceFile, line, character, str);
		}

		#region Buffer Write Interpreted

		private void BufferWriteInterpreted(string buffer)
		{
			BufferWriteInterpreted(buffer, 0, 0);
		}

		private void BufferWriteInterpreted(ConsoleColorExt colour, string buffer, int paddingLeft, int paddingRight)
		{
			ConsoleColorExt col = ForegroundColor;

			if (colour != ConsoleColorExt.Inhreit)
			{
				m_ForegroundColor = colour;
			}

			BufferWriteInterpreted(buffer, paddingLeft, paddingRight);

			m_ForegroundColor = col;
		}

		private void BufferWriteInterpreted(string buffer, int paddingLeft, int paddingRight)
		{
			// It is unfortunate that this method must be internalised to this class from ConsoleFormatter
			// i would hope that i could move it back. 

			int maxWidth = BufferWidth - (paddingLeft + paddingRight);

			string prefix = new string(' ', paddingLeft);

			int lastIndex = 0;
			Stack<ConsoleColorExt> stack = new Stack<ConsoleColorExt>();

			foreach (Match match in ConsoleFormatter.FormatRegex.Matches(buffer))
			{
				if (match.Groups["Tag"].Success)
				{
					// start tag 
					// parse the tags inner value
					// e.g. c:# (where # is the name or ID of the colour to use (From ConsoleColourExt) 
					// add the parsed colour to the stack 

					ConsoleColorExt col = ConsoleFormatter.ParseColour(match.Groups["Inner"].Value, Theme);

					stack.Push(m_ForegroundColor);

					m_ForegroundColor = col;
				}
				else if (match.Groups["EndTag"].Success)
				{
					// end tag 
					// handle stack changes
					if (stack.Count >= 0)
					{
						m_ForegroundColor = stack.Pop();
					}
					else
					{
						throw new Exception(string.Format(Strings.ConsoleInterpreter_UnexpectedEndTag, match.Index));
					}
				}
				else if (match.Groups["Text"].Success)
				{
					string wholeMessage = ConsoleFormatter.UnescapeString(match.Value);

					List<string> lines = ConsoleFormatter.SplitLinebreaks(wholeMessage);

					foreach (string line in lines)
					{
						string str = line;

						if (str == "\n" || str == Environment.NewLine)
						{
							BufferWriteLine("");
							lastIndex = 0;
						}
						else
						{

							while (str.Length > 0)
							{
								if (lastIndex + str.Length > maxWidth)
								{
									int lastWord = str.LastIndexOf(' ', maxWidth - lastIndex, maxWidth - lastIndex);

									if (lastWord <= 0)
									{
										lastWord = maxWidth - lastIndex;
									}

									string toRender;

									if (lastIndex > 0)
									{
										toRender = str.Substring(0, lastWord);
									}
									else
									{
										toRender = prefix + str.Substring(0, lastWord);
									}

									if (BufferWidth == lastIndex + toRender.Length)
									{
										BufferWrite(toRender);
									}
									else
									{
										BufferWriteLine(toRender);
									}

									str = str.Substring(lastWord + 1);

									lastIndex = 0;
								}
								else
								{
									string toRender = str;

									if (lastIndex <= 0)
									{
										toRender = prefix + str;
									}

									BufferWrite(toRender);

									lastIndex += str.Length;

									str = "";
								}
							}
						}
					}
				}
			}
		}

		private void BufferWriteInterpretedLine(string buffer)
		{
			BufferWriteInterpreted(buffer + Environment.NewLine);
		}

		#endregion

		#endregion

		#region IConsole Members

		public string ApplicationBuildReportPrefix
		{
			get
			{
				return RC.Sys.ApplicationBuildReportPrefix;
			}
			set
			{
				RC.Sys.ApplicationBuildReportPrefix = value;
			}
		}

		public ConsoleVerbosity Verbosity
		{
			get
			{
				return m_Verbosity;
			}
			set
			{
				m_Verbosity = value;
			}
		}

		public bool DefaultPromptAnswer
		{
			get
			{
				return RC.Sys.DefaultPromptAnswer;
			}
			set
			{
				RC.Sys.DefaultPromptAnswer = value;
			}
		}

		public bool UseDefaultPromptAnswer
		{
			get
			{
				return RC.Sys.UseDefaultPromptAnswer;
			}
			set
			{
				RC.Sys.UseDefaultPromptAnswer = value;
			}
		}

		public bool WarningsAsErrors
		{
			get
			{
				return RC.Sys.WarningsAsErrors;
			}
			set
			{
				RC.Sys.WarningsAsErrors = value;
			}
		}

		public bool ReportWarnings
		{
			get
			{
				return RC.Sys.ReportWarnings;
			}
			set
			{
				RC.Sys.ReportWarnings = value;
			}
		}

		public bool IsBuildMode
		{
			get
			{
				return RC.Sys.IsBuildMode;
			}
			set
			{
				RC.Sys.IsBuildMode = value;
			}
		}

		public bool CanManipulateBuffer
		{
			get { return false; }
		}

		public int BufferWidth
		{
			get
			{
				return m_BufferWidth;
			}
			set
			{
				lock (m_Lock)
				{
					m_BufferWidth = value;
				}
			}
		}

		public int BufferHeight
		{
			get
			{
				return m_BufferHeight;
			}
			set
			{
				lock (m_Lock)
				{
					m_BufferHeight = value;
				}
			}
		}

		public int CursorLeft
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public int CursorTop
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public int CursorSize
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string Title
		{
			get
			{
				return m_Title; 
			}
			set
			{
				m_Title = value; 
			}
		}

		public Colors.ConsoleColorTheme Theme
		{
			get
			{
				return m_Theme; 
			}
			set
			{
				lock (m_Lock)
				{
					m_Theme = value;
				}
			}
		}

		public ConsoleColorExt ForegroundColor
		{
			get
			{
				return m_ForegroundColor;
			}
			set
			{
				lock (m_Lock)
				{
					m_ForegroundColor = value;
				}
			}
		}

		public ConsoleColorExt BackgroundColor
		{
			get
			{
				return m_BackgroundColor;
			}
			set
			{
				lock (m_Lock)
				{
					m_BackgroundColor = value;
				}
			}
		}

		public ConsoleThemeColor ForegroundThemeColor
		{
			set { ForegroundColor = m_Theme[value]; }
		}

		public ConsoleThemeColor BackgroundThemeColor
		{
			set { BackgroundColor = m_Theme[value]; }
		}

		public ConsoleColorState ColorState
		{
			get 
			{ 
				return new ConsoleColorState(ForegroundColor, BackgroundColor); 
			}
			set
			{
				lock (m_Lock)
				{
					m_ForegroundColor = value.ForegroundColor;
					m_BackgroundColor = value.BackgroundColor;
				}
			}
		}

		public void ResetColor()
		{
			ColorState = m_OriginalState; 
		}

		public void SetCursorPosition(int left, int top)
		{
			throw new NotImplementedException();
		}

		public void Clear()
		{
			lock (m_Lock)
			{
				m_ConsoleText.Clear(); 
			}

			OnContentsChanged(); 
		}

		public bool KeyAvailable
		{
			get { throw new NotImplementedException(); }
		}

		public int Read()
		{
			throw new NotImplementedException();
		}

		public ConsoleKeyInfo ReadKey()
		{
			throw new NotImplementedException();
		}

		public ConsoleKeyInfo ReadKey(bool intercept)
		{
			throw new NotImplementedException();
		}

		public string ReadLine()
		{
			throw new NotImplementedException();
		}

		public ConsoleKeyInfo PromptForKey(string message, bool intercept, bool throwException)
		{
			throw new NotImplementedException();
		}

		public string PromptForLine(string message, bool throwException)
		{
			throw new NotImplementedException();
		}

		public bool ShouldWrite(ConsoleVerbosity verbosity)
		{
			return (int)verbosity <= (int)m_Verbosity;
		}

		public void Write(string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{					
					BufferWrite(str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.Write(str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void Write(ConsoleVerbosity level, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{					
					BufferWrite(str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.Write(level, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void Write(ConsoleVerbosity level, ConsoleColorExt colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{
					BufferWrite(colour, str);
					updated = true; 
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.Write(level, colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void Write(ConsoleVerbosity level, ConsoleThemeColor colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{
					BufferWrite(Theme[colour], str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.Write(level, colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void Write(ConsoleColorExt colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{
					BufferWrite(colour, str);
					updated = true;
				}
				
				if (m_EchoToSystemConsole)
				{
					RC.Sys.Write(colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void Write(ConsoleThemeColor colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{
					BufferWrite(Theme[colour], str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.Write(colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(ConsoleVerbosity level)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{
					BufferWriteLine("");
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(level);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine()
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{
					BufferWriteLine("");
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine();
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{
					BufferWriteLine(str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(ConsoleVerbosity level, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{
					BufferWriteLine(str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(level, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(ConsoleVerbosity level, ConsoleColorExt colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{
					BufferWriteLine(colour, str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(level, colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(ConsoleColorExt colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{
					BufferWriteLine(colour, str);
					updated = true;
				}	

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(ConsoleVerbosity level, ConsoleThemeColor colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(level) == true)
				{
					BufferWriteLine(Theme[colour], str);
					updated = true;
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(level, colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteLine(ConsoleThemeColor colour, string str)
		{
			bool updated = false;

			lock (m_Lock)
			{
				if (ShouldWrite(ConsoleVerbosity.Normal) == true)
				{
					BufferWriteLine(Theme[colour], str);
					updated = true;
				}	

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteLine(colour, str);
				}
			}

			if (updated == true) OnContentsChanged();
		}

		public void WriteWrapped(ConsoleColorExt colour, string message, int paddingLeft, int paddingRight)
		{
			lock (m_Lock)
			{
				BufferWriteWrapped(colour, message, paddingLeft, paddingRight);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWrapped(colour, message, paddingLeft, paddingRight);
				}
			}

			OnContentsChanged();
		}

		public void WriteWrapped(ConsoleThemeColor colour, string message, int paddingLeft, int paddingRight)
		{
			lock (m_Lock)
			{
				BufferWriteWrapped(Theme[colour], message, paddingLeft, paddingRight);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWrapped(colour, message, paddingLeft, paddingRight);
				}
			}

			OnContentsChanged();
		}

		public void WritePrompt(string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Prompt, ConsoleThemeColor.PromptColor1, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WritePrompt(str);
				}
			}

			OnContentsChanged();
		}

		public void WritePrompt(ConsoleColorExt colour, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Prompt, colour, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WritePrompt(colour, str);
				}
			}

			OnContentsChanged();
		}

		public void WritePrompt(ConsoleThemeColor colour, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Prompt, colour, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WritePrompt(colour, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteError(int id, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, ConsoleThemeColor.ErrorColor1, id, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteError(id, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteError(int id, string sourceFile, int line, int character, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, ConsoleThemeColor.ErrorColor1, id, sourceFile, line, character, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteError(id, sourceFile, line, character, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteError(ConsoleColorExt colour, int id, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, colour, id, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteError(colour, id, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteError(ConsoleThemeColor colour, int id, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, colour, id, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteError(colour, id, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteWarning(int id, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Warning, ConsoleThemeColor.WarningColor1, id, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWarning(id, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteWarning(ConsoleColorExt colour, int id, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Warning, colour, id, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWarning(colour, id, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteWarning(ConsoleThemeColor colour, int id, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Warning, colour, id, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWarning(colour, id, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteWarning(ConsoleColorExt colour, int id, string sourceFile, int line, int character, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Warning, colour, id, sourceFile, line, character, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWarning(colour, id, sourceFile, line, character, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteWarning(ConsoleThemeColor colour, int id, string sourceFile, int line, int character, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Warning, colour, id, sourceFile, line, character, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteWarning(colour, id, sourceFile, line, character, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteException(int id, Exception ex)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, ConsoleThemeColor.ErrorColor1, id, ex.Message);

				if (Verbosity == ConsoleVerbosity.Debug)
				{
					BufferWriteStackTrace(ex.StackTrace);
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteException(id, ex);
				}
			}

			OnContentsChanged();
		}

		public void WriteException(int id, string sourceFile, int line, int character, Exception ex)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, ConsoleThemeColor.ErrorColor1, id, sourceFile, line, character, ex.Message);

				if (Verbosity == ConsoleVerbosity.Debug)
				{
					BufferWriteStackTrace(ex.StackTrace);
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteException(id, sourceFile, line, character, ex);
				}
			}

			OnContentsChanged();
		}

		public void WriteException(int id, string title, Exception ex)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, ConsoleThemeColor.ErrorColor1, id, title + Environment.NewLine + ex.Message);

				if (Verbosity == ConsoleVerbosity.Debug)
				{
					BufferWriteStackTrace(ex.StackTrace);
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteException(id, title, ex);
				}
			}

			OnContentsChanged();
		}

		public void WriteException(int id, string sourceFile, int line, int character, string title, Exception ex)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(ConsoleMessage.Error, ConsoleThemeColor.ErrorColor1, id, sourceFile, line, character, title + Environment.NewLine + ex.Message);

				if (Verbosity == ConsoleVerbosity.Debug)
				{
					BufferWriteStackTrace(ex.StackTrace);
				}

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteException(id, sourceFile, line, character, title, ex);
				}
			}

			OnContentsChanged();
		}

		public void WriteStackTrace(string trace)
		{
			lock (m_Lock)
			{
				BufferWriteStackTrace(trace);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteStackTrace(trace);
				}
			}

			OnContentsChanged();
		}

		public void WriteMessage(ConsoleMessage type, ConsoleColorExt colour, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(type, colour, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteMessage(type, colour, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteMessage(ConsoleMessage type, ConsoleThemeColor colour, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(type, colour, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteMessage(type, colour, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteMessage(ConsoleMessage type, ConsoleColorExt colour, int errorId, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(type, colour, errorId, str);
				
				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteMessage(type, colour, errorId, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteMessage(ConsoleMessage type, ConsoleColorExt colour, int errorId, string sourceFile, int line, int character, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(type, colour, errorId, sourceFile, line, character, str);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteMessage(type, colour, errorId, sourceFile, line, character, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteMessage(ConsoleMessage type, ConsoleThemeColor colour, int errorId, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(type, colour, errorId, str);
				
				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteMessage(type, colour, errorId, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteMessage(ConsoleMessage type, ConsoleThemeColor colour, int errorId, string sourceFile, int line, int character, string str)
		{
			lock (m_Lock)
			{
				BufferWriteMessage(type, colour, errorId, sourceFile, line, character, str);
				
				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteMessage(type, colour, errorId, sourceFile, line, character, str);
				}
			}

			OnContentsChanged();
		}

		public void WriteInterpreted(string buffer)
		{
			lock (m_Lock)
			{
				BufferWriteInterpreted(buffer);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteInterpreted(buffer);
				}
			}
		}

		public void WriteInterpreted(string buffer, int paddingLeft, int paddingRight)
		{
			lock (m_Lock)
			{
				BufferWriteInterpreted(buffer, paddingLeft, paddingRight);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteInterpreted(buffer, paddingLeft, paddingRight);
				}
			}

			OnContentsChanged();
		}

		public void WriteInterpreted(ConsoleColorExt colour, string buffer, int paddingLeft, int paddingRight)
		{
			lock (m_Lock)
			{
				BufferWriteInterpreted(colour, buffer, paddingLeft, paddingRight);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteInterpreted(colour, buffer, paddingLeft, paddingRight);
				}
			}

			OnContentsChanged();
		}

		public void WriteInterpreted(ConsoleThemeColor colour, string buffer, int paddingLeft, int paddingRight)
		{
			lock (m_Lock)
			{
				BufferWriteInterpreted(Theme[colour], buffer, paddingLeft, paddingRight);

				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteInterpreted(colour, buffer, paddingLeft, paddingRight);
				}
			}

			OnContentsChanged();
		}

		public void WriteInterpretedLine(string buffer)
		{
			lock (m_Lock)
			{
				BufferWriteInterpretedLine(buffer);
				
				if (m_EchoToSystemConsole)
				{
					RC.Sys.WriteInterpretedLine(buffer);
				}
			}

			OnContentsChanged();
		}

		#endregion
	}
}
